package com.wang.interview.data_structures_and_algorithms.a01_sparse_array;

import java.io.*;
import java.util.LinkedList;
import java.util.Random;

import static com.wang.interview.data_structures_and_algorithms.a01_sparse_array.FirstTest.initArray;
import static com.wang.interview.data_structures_and_algorithms.a01_sparse_array.FirstTest.priArr;

/**
 * @author: wang
 * @date: 2021/8/2 21:24
 * @description:
 */
public class FirstTest {
    public static void main(String[] args) throws IOException {

        /**
         * 二维数组的长度：
         * 1、arr1.length = 6
         * 2、arr1[i].length = 7
         */
        int[][] arr1 = new int[6][6];
        initArray(arr1);                    // 初始化数组
        priArr(arr1);

        int[][] res1 = toSparseArr(arr1);   // 转为稀疏数组
        priArr(res1);

        String path = saveSparseArr(res1);      // 持久化稀疏数组

        int[][] ints = readSparseArr(path);     // 从文件读稀疏数组
        priArr(ints);

        int[][] res2 = toNormalArr(res1);       // 将稀疏数组还原成原数组
        priArr(res2);
    }

    public static int[][] readSparseArr(String path) throws IOException {
        /*String path = FirstTest.class.getResource("sparseArr.data").getPath();
        path = path.replace("target/classes", "src/main/java").substring(1);*/
        File file = new File(path);
        BufferedReader br = new BufferedReader(new FileReader(file));
        int length = Integer.parseInt(br.readLine());       // 读取数组长度
        String[] split = br.readLine().split(",");
        int i = Integer.parseInt(split[0]);
        int j = Integer.parseInt(split[1]);
        int k = Integer.parseInt(split[2]);
        int[][] arr = new int[length][3];
        arr[0][0] = i;
        arr[0][1] = j;
        arr[0][2] = k;
        int x = 1;
        String res = "";
        while ((res = br.readLine()) != null){
            split = res.split(",");
            arr[x][0] = Integer.parseInt(split[0]);
            arr[x][1] = Integer.parseInt(split[1]);
            arr[x++][2] = Integer.parseInt(split[2]);
        }
        return arr;
    }

    public static String saveSparseArr(int[][] arr) throws IOException {
        //File file = new File("E:\\AJava\\idea_code\\2021-07-12-interview-starer\\src\\main\\java\\com\\wang\\interview\\data_structures_and_algorithms\\a01_sparse_array\\sparseArr.data");
        // /E: 到当前类的包路劲，注意最前面有个/,而且这个方法获取的是target路径的：target/classes 替换为 src/main/java
        String path = FirstTest.class.getResource("").getPath();

        // 去掉首 /，替换target
        path = path.replace("target/classes", "src/main/java").substring(1)+"sparseArr.data";
        File file = new File(path);

        /*if (file.exists()) {
            System.out.println(file.getPath());                  // 写文件，不需要这个文件存在，地址正确自动创建
        }*/

        //BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8));
        // 这种方式不支持设置编码，推荐使用上面的转换流
        BufferedWriter bw = new BufferedWriter(new FileWriter(file),1024);
        bw.write(arr.length+"");
        bw.newLine();
        bw.flush();
        for (int i = 0; i < arr.length; i++) {
            bw.write(arr[i][0]+","+arr[i][1]+","+arr[i][2]);
            bw.newLine();
            bw.flush();
        }
        bw.close();
        return path;
    }


    /**
     * 给二维数组初始化值
     * @param arr
     */
    public static void initArray(int[][] arr){
        int length = arr.length;
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                arr[i][j] = random.nextInt(j+1);
                if (arr[i][j] % 2.1f < 1.9){                 // 余数一定小于模数，用小数是为了让计算提升为float,余数的范围就在0到2.1之间
                    arr[i][j] = 0;
                }
            }
        }
    }

    /**
     * 打印二维数组
     */
    public static void priArr(int[][] arr){
        for (int[] es : arr) {
            for (int e : es) {
                System.out.print(e + "\t");
            }
            System.out.println();
        }
        System.out.println("-----------------------------");
    }

    /**
     * 将二维数组转为稀疏数组
     * @param arr
     */
    public static int[][] toSparseArr(int[][] arr){
        //第一步，遍历获取所有有效的值的个数和信息
        int count = 0;
        LinkedList<Integer> list = new LinkedList<>();  // 使用链表，方便增加
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                if (arr[i][j] != 0){
                    count++;
                    list.add(i);
                    list.add(j);
                    list.add(arr[i][j]);
                }
            }
        }
        int[][] result = new int[count+1][3];
        // 第一行第一列存原数组的行数
        result[0][0] = arr.length;
        // 第一行第二列存原数组的列数
        result[0][1] = arr[0].length;
        // 第一行第三列存原数组的有效值的数量
        result[0][2] = count;
        for (int i = 1; i < result.length; i++) {
            for (int j = 0; j < result[i].length; j++) {
                result[i][j] = list.pop();
            }
        }
        return result;
    }

    /**
     * 将稀疏数组转为二维数组
     * @param arr
     */
    public static int[][] toNormalArr(int[][] arr){
        int[][] result = new int[arr[0][0]][arr[0][1]];
        for (int i = 1; i < arr.length; i++) {
            result[arr[i][0]][arr[i][1]] = arr[i][2];
        }
        return result;
    }
}

/**
 * 证明 pop 会从左侧弹出数据，原长减一
 */
class A{
    public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        System.out.println(list.pop());  // 1
        System.out.println(list);        // [2, 3]
    }
}

/**
 * 证明 整数模小数，余数是小数
 */
class B{
    public static void main(String[] args) {
        int a = 12;
        System.out.printf("%.6f",a%1.3);  // 0.300000
    }
}

/**
 * 证明，凡是涉及对象的持久化，最好都用序列化完成，简单又快捷
 */
class C{
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        int[][] a = new int[6][6];
        initArray(a);
        String path = "E:\\AJava\\idea_code\\2021-07-12-interview-starer\\src\\main\\java\\com\\wang\\interview\\data_structures_and_algorithms\\a01_sparse_array\\sparseArr.data";
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
        oos.writeObject(a);
        oos.close();
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File(path)));
        int[][] ints = (int[][]) ois.readObject();
        priArr(ints);
    }
}
